#!/usr/bin/env ruby
#
# Created by Jerry Luk on 2008-05-01
# Copyright (c) 2008. All rights reserved.

# Extend/Patch RSS module

module RSS
  class Element    
    private
    def tag(indent, additional_attrs={}, &block)
      next_indent = indent + INDENT

      attrs = collect_attrs
      return "" if attrs.nil?

      # return "" unless have_required_elements?

      attrs.update(additional_attrs)
      start_tag = make_start_tag(indent, next_indent, attrs.dup)

      if block
        content = block.call(next_indent)
      else
        content = []
      end

      if content.is_a?(String)
        content = [content]
        start_tag << ">"
        end_tag = "</#{full_name}>"
      else
        content = content.reject{|x| x.empty?}
        if content.empty?
          return "" if attrs.empty?
          end_tag = "/>"
        else
          start_tag << ">\n"
          end_tag = "\n#{indent}</#{full_name}>"
        end
      end
      
      start_tag + content.join("\n") + end_tag
    end
  end
end

module RSS
  module Utils
    class << self
      def to_class_name_with_prefix(name, prefix='')
        self.to_class_name(prefix + '_' + name)
      end
    end
  end
  
  module BaseModel
    
    def base_append_features(klass, element_name_infos, prefix, uri)
      # TODO: Figure out a way to exclude RSpec in the test code but not here
      return if klass.instance_of?(Module) or klass.to_s.include?('Spec::')
      element_name_infos.each do |name, plural_name|
        plural = plural_name || "#{name}s"
        full_name = "#{prefix}_#{name}"
        full_plural_name = "#{prefix}_#{plural}"
        klass_name = Utils.to_class_name_with_prefix(name, prefix)
        klass.install_must_call_validator(prefix, uri)
        klass.install_have_children_element(name, uri, "*",
                                            full_name, full_plural_name)
        klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0))
          remove_method :#{full_name}
          remove_method :#{full_name}=
          remove_method :set_#{full_name}

          def #{full_name}
            @#{full_name}.first
          end
          
          def #{full_name}=(new_value)
            @#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value)
          end
          alias set_#{full_name} #{full_name}=
          if '#{full_name}'.underscore != '#{full_name}'
            alias_method '#{full_name}'.underscore.to_sym, '#{full_name}'.to_sym
            alias_method '#{full_name}='.underscore.to_sym, '#{full_name}='.to_sym
            alias_method '#{full_plural_name}'.underscore.to_sym, '#{full_plural_name}'.to_sym
            # alias_method '#{full_plural_name}='.underscore.to_sym, '#{full_plural_name}='.to_sym
          end
        EOC
      end
      # klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0))
      #   if method_defined?(:date)
      #     alias date_without_#{GDATA_PREFIX}_date= date=
      # 
      #     def date=(value)
      #       self.date_without_#{GDATA_PREFIX}_date = value
      #       self.#{GDATA_PREFIX}_date = value
      #     end
      #   else
      #     alias date #{GDATA_PREFIX}_date
      #     alias date= #{GDATA_PREFIX}_date=
      #   end
      # EOC
    end
    
    def create_class(name, plural_name, prefix, uri, content=true)
      module_eval(<<-EOC, *get_file_and_line_from_caller(0))
        class #{Utils.to_class_name_with_prefix(name, prefix)} < Element
          include RSS10
          
          content_setup if #{content}

          class << self
            def required_prefix
              # GDATA_PREFIX
              '#{prefix}'
            end
        
            def required_uri
              # GDATA_URI
              '#{uri}'
            end
          end
               
          @tag_name = #{name.dump}

          # alias_method(:value, :content)
          # alias_method(:value=, :content=)
          
          def initialize(*args)
            if Utils.element_initialize_arguments?(args)
              super
            else
              super()
              self.content = args[0] if #{content}
            end
          end
      
          def full_name
            # tag_name_with_prefix(GDATA_PREFIX)
            tag_name_with_prefix('#{prefix}')
          end

          def maker_target(target)
            target.new_#{name}
          end

          # #{name} does not work with "when" since "when" is a keyword
          # def setup_maker_attributes(#{name})
          #   #{name}.content = content
          # end
          
          def setup_maker_attributes(target)
            target.content = content
          end
          
          ATTRIBUTES.each do |name, uri, required, type|
            install_get_attribute(name, uri, required, type)
            if name.underscore != name
              alias_method name.underscore, name 
              alias_method name.underscore+'=', name+'='
            end
          end
        end
      EOC
    end
  end
end
